import type {
  AxiosInstance,
  AxiosRequestConfig,
  AxiosResponse,
  InternalAxiosRequestConfig,
  AxiosError,
} from "axios";

import axios from "axios";
import NProgress from "nprogress";

import useUserStore from "@/stores/user";

NProgress.configure({
  easing: "ease", // 动画方式
  speed: 500, // 递增进度条的速度
  showSpinner: true, // 是否显示加载ico
  trickleSpeed: 200, // 自动递增间隔
  minimum: 0.3, // 初始化时的最小百分比
});

interface Result<T = unknown> {
  message: string;
  code: number;
  data: T;

  [key: string]: any; // 其他的任意类型
}

const baseURL = import.meta.env.VITE_APP_BASE_API;
const timeout = import.meta.env.VITE_APP_PREVENT_DUPLICATE_SUBMISSIONS;

class Request {
  // axios 实例
  instance: AxiosInstance;
  // 基础配置，url和超时时间
  baseConfig: AxiosRequestConfig = {
    baseURL,
    timeout,
    headers: {
      "Content-Type": "application/json;charset=utf-8",
    },
  };

  constructor(config: AxiosRequestConfig = {}) {
    // 使用axios.create创建axios实例
    this.instance = axios.create(Object.assign(this.baseConfig, config));
    this.instance.interceptors.request.use(
      (config: InternalAxiosRequestConfig) => {
        NProgress.start();
        return config;
      },
      (err: AxiosError) => {
        NProgress.done();
        return Promise.reject(err);
      }
    );
    this.instance.interceptors.response.use(
      (response: AxiosResponse) => {
        const data = response.data;
        if (data.msg === "NOTLOGIN") {
          useUserStore().closeAll();
        }
        console.log("response", response);
        NProgress.done();
        const responseType = response.request.responseType;
        // 二进制数据则直接返回
        if (responseType === "blob" || responseType === "arraybuffer") {
          return response;
        }
        return response.data;
      },
      (err: AxiosError) => {
        NProgress.done();
        return Promise.reject(err.response);
      }
    );
  }

  // 定义请求方法
  public request(config: AxiosRequestConfig): Promise<AxiosResponse> {
    return this.instance.request(config);
  }

  public get<T = any>(
    url: string,
    config?: AxiosRequestConfig
  ): Promise<Result<T>> {
    return this.instance.get(url, config);
  }

  public post<T = any>(
    url: string,
    data?: any,
    config?: AxiosRequestConfig
  ): Promise<Result<T>> {
    return this.instance.post(url, data, config);
  }

  public put<T = any>(
    url: string,
    data?: any,
    config?: AxiosRequestConfig
  ): Promise<Result<T>> {
    return this.instance.put(url, data, config);
  }

  public delete<T = any>(
    url: string,
    config?: AxiosRequestConfig
  ): Promise<Result<T>> {
    return this.instance.delete(url, config);
  }
}

export { Request };

export default new Request();
